package com.monochromebytes.mononet.test.network;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;


import com.monochromebytes.mononet.stub.Stub;
import com.monochromebytes.mononet.stub.StubSocket;
import com.monochromebytes.mononet.stub.StubSocketListener;

import com.monochromebytes.mononet.test.Body;


public class ServerNetworkController extends NetworkController implements StubSocketListener {

    private final ArrayList<Stub> stubs;
    private final Timer           timer;
    private Body                  body;

    public ServerNetworkController(InetSocketAddress localAddress) throws IOException {
        super(localAddress);

        socket.addStubListener(this);

        this.stubs = new ArrayList<Stub>();

        this.timer = new Timer();
        this.timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    SnapshotMessage snapshot = new SnapshotMessage(body);
                    
                    for (Iterator<Stub> iterator = stubs.iterator(); iterator.hasNext();) {
                        Stub stub = iterator.next();
                        stub.send(snapshot, 1000);
                        stub.checkForLostObjects();
                        currentNumberOfSentObjects++;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }, 1000, 50);
        this.timer.schedule(new TimerTask() {
            @Override
            public void run() {
                for (Iterator<Stub> iterator = stubs.iterator(); iterator.hasNext();) {
                    Stub stub = iterator.next();
                    long lastCommunication = stub.getLastReceivedObjectTimestamp();
                    long now = System.currentTimeMillis();
                    if (now - lastCommunication > 1000) {
                        System.out.println("Client disconnected: "
                                + stub.getAddress().getRemoteAddress());
                        stub.removeFromSocket();
                        iterator.remove();
                    }
                }
            }
        }, 1000, 100);
    }

    @Override
    public void update(int delta) {
        for (Stub stub : this.stubs) {
            while (stub.hasIncomingObjects()) {
                stub.handleNextObject();
            }
        }
    }

    @Override
    public void incomingStub(Stub stub) {
        System.out.println("Client connected: " + stub.getAddress().getRemoteAddress());
        synchronized (this.stubs) {
            this.stubs.add(stub);
        }
        stub.addObjectListener(this);
    }

    public void setBody(Body body) {
        this.body = body;
    }

    public int getNumberOfClients() {
        return this.stubs.size();
    }

    @Override
    public void socketClosed(StubSocket socket, IOException e) {
        this.timer.cancel();
        if (e != null) {
            System.err.println("Socket has been closed.");
            e.printStackTrace();
        }
    }

    @Override
    public void socketOpened(StubSocket socket) {
        // Do nothing.
    }
    
    @Override
    public void receiveObject(Object object, Stub stub) {
        super.receiveObject(object, stub);
        
        if (object instanceof PingMessage) {
            try {
                stub.send(object, 1000);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
